import configparser
import csv
import json
import logging
import os
from dataclasses import dataclass
from datetime import datetime
from enum import Enum
from typing import Any, Dict, List, Optional, Set, Tuple

from PySide6.QtCore import QObject, Signal

class ChangeType(Enum):
    """数据变更类型"""
    INSERT = "insert"
    UPDATE = "update"
    DELETE = "delete"
    COLUMN_ADD = "column_add"
    COLUMN_REMOVE = "column_remove"
    COLUMN_REORDER = "column_reorder"
    COLUMN_MARK = "column_mark"


@dataclass
class DataChange:
    """数据变更记录"""
    timestamp: str
    change_type: ChangeType
    row_index: Optional[int]
    column_index: Optional[int]
    old_value: Optional[str]
    new_value: Optional[str]
    full_row_data: Optional[List[str]]
    user_action: str
    description: str


class DataManager:
    """数据管理器 - 负责数据的核心操作和修改记录"""
    
    def __init__(self, config_file: str = "config.ini", event_bus=None):
        self._data: List[List[str]] = []
        self._headers: List[str] = []
        self._column_order: List[int] = []
        self._marked_columns: Set[int] = set()
        self._modified_cells: Set[Tuple[int, int]] = set()  # (row, col) 修改过的单元格
        self._deleted_rows: Set[int] = set()  # 删除的行
        self._added_rows: Set[int] = set()    # 新增的行
        self._disabled_rows: Set[int] = set() # 禁用的行
        
        # 事件总线
        self.event_bus = event_bus
        
        # 加载配置
        self._config = self._load_config(config_file)
        
        # 日志设置
        self._setup_logging()
        
    def _load_config(self, config_file: str) -> configparser.ConfigParser:
        """加载配置文件"""
        # 使用BasicInterpolation避免%字符被误解析
        config = configparser.ConfigParser(interpolation=None)
        
        # 如果配置文件不存在，创建默认配置
        if not os.path.exists(config_file):
            config['logging'] = {
                'output_mode': 'both',
                'log_file': 'data_changes.log',
                'log_level': 'INFO',
                'log_format': '%(asctime)s - %(levelname)s - %(message)s',
                'enabled': 'true'
            }
            with open(config_file, 'w', encoding='utf-8') as f:
                config.write(f)
        else:
            config.read(config_file, encoding='utf-8')
            
        return config
        
    def _setup_logging(self):
        """设置日志记录"""
        if not self._config.getboolean('logging', 'enabled', fallback=True):
            # 如果日志被禁用，创建一个空的logger
            self._logger = logging.getLogger(__name__)
            self._logger.addHandler(logging.NullHandler())
            return
            
        # 获取配置
        output_mode = self._config.get('logging', 'output_mode', fallback='both')
        log_file = self._config.get('logging', 'log_file', fallback='data_changes.log')
        log_level_str = self._config.get('logging', 'log_level', fallback='INFO')
        log_format = self._config.get('logging', 'log_format', 
                                    fallback='%(asctime)s - %(levelname)s - %(message)s')
        
        # 转换日志级别
        log_level = getattr(logging, log_level_str.upper(), logging.INFO)
        
        # 创建logger
        self._logger = logging.getLogger(__name__)
        self._logger.setLevel(log_level)
        
        # 清除现有的handlers
        self._logger.handlers.clear()
        
        # 创建formatter
        formatter = logging.Formatter(log_format)
        
        # 根据输出模式添加handlers
        if output_mode in ['file', 'both']:
            file_handler = logging.FileHandler(log_file, encoding='utf-8-sig')
            file_handler.setFormatter(formatter)
            self._logger.addHandler(file_handler)
            
        if output_mode in ['console', 'both']:
            console_handler = logging.StreamHandler()
            console_handler.setFormatter(formatter)
            self._logger.addHandler(console_handler)
    
    def _log_change(self, change: DataChange):
        """记录数据变更"""
        # 记录到日志文件
        self._logger.info(f"数据变更: {change.description}")
        
        # 保存详细变更记录到JSON文件
        change_file = f"changes_{datetime.now().strftime('%Y%m%d')}.json"
        changes = []
        
        if os.path.exists(change_file):
            try:
                with open(change_file, 'r', encoding='utf-8') as f:
                    changes = json.load(f)
            except:
                changes = []
        
        # 转换为可序列化的字典
        change_dict = {
            'timestamp': change.timestamp,
            'change_type': change.change_type.value,  # 使用枚举值而不是枚举对象
            'row_index': change.row_index,
            'column_index': change.column_index,
            'old_value': change.old_value,
            'new_value': change.new_value,
            'full_row_data': change.full_row_data,
            'user_action': change.user_action,
            'description': change.description
        }
        
        changes.append(change_dict)
        
        with open(change_file, 'w', encoding='utf-8') as f:
            json.dump(changes, f, ensure_ascii=False, indent=2)
    
    def _update_row_indices_after_insert(self, inserted_row: int):
        """插入行后更新行索引"""
        # 更新修改过的单元格索引
        new_modified_cells = set()
        for row, col in self._modified_cells:
            if row >= inserted_row:
                new_modified_cells.add((row + 1, col))
            else:
                new_modified_cells.add((row, col))
        self._modified_cells = new_modified_cells
        
        # 更新新增行索引
        new_added_rows = set()
        for row in self._added_rows:
            if row >= inserted_row:
                new_added_rows.add(row + 1)
            else:
                new_added_rows.add(row)
        self._added_rows = new_added_rows
        
        # 更新删除行索引
        new_deleted_rows = set()
        for row in self._deleted_rows:
            if row >= inserted_row:
                new_deleted_rows.add(row + 1)
            else:
                new_deleted_rows.add(row)
        self._deleted_rows = new_deleted_rows
        
        # 更新禁用行索引
        new_disabled_rows = set()
        for row in self._disabled_rows:
            if row >= inserted_row:
                new_disabled_rows.add(row + 1)
            else:
                new_disabled_rows.add(row)
        self._disabled_rows = new_disabled_rows
    
    def _update_row_indices_after_delete(self, deleted_row: int):
        """删除行后更新行索引"""
        # 更新修改过的单元格索引
        new_modified_cells = set()
        for row, col in self._modified_cells:
            if row > deleted_row:
                new_modified_cells.add((row - 1, col))
            elif row < deleted_row:
                new_modified_cells.add((row, col))
        self._modified_cells = new_modified_cells
        
        # 更新新增行索引
        new_added_rows = set()
        for row in self._added_rows:
            if row > deleted_row:
                new_added_rows.add(row - 1)
            elif row < deleted_row:
                new_added_rows.add(row)
        self._added_rows = new_added_rows
    
    def get_data(self) -> Tuple[List[List[str]], List[str]]:
        """获取数据"""
        return self._data, self._headers
    
    def get_row_count(self) -> int:
        """获取行数"""
        return len(self._data)
    
    def get_column_count(self) -> int:
        """获取列数"""
        return len(self._headers)
    
    def get_headers(self) -> List[str]:
        """获取表头"""
        return self._headers.copy()
    
    def get_cell_data(self, row: int, col: int) -> str:
        """获取单元格数据"""
        if 0 <= row < len(self._data) and 0 <= col < len(self._headers):
            return self._data[row][col]
        return ""
    
    def set_cell_data(self, row: int, col: int, value: str) -> bool:
        """设置单元格数据"""
        if 0 <= row < len(self._data) and 0 <= col < len(self._headers):
            old_value = self._data[row][col]
            self._data[row][col] = value
            self._modified_cells.add((row, col))
            
            # 发布事件
            if self.event_bus:
                from src.events import CellEditedEvent
                event = CellEditedEvent(row, col, old_value, value)
                self.event_bus.publish(event)
            
            # 记录变更
            change = DataChange(
                timestamp=datetime.now().isoformat(),
                change_type=ChangeType.UPDATE,
                row_index=row,
                column_index=col,
                old_value=old_value,
                new_value=value,
                full_row_data=self._data[row].copy(),
                user_action="cell_update",
                description=f"更新单元格 [{row}, {col}]: '{old_value}' -> '{value}'"
            )
            self._log_change(change)
            
            return True
        return False
    
    def add_row(self, row_data: List[str]) -> bool:
        """添加行"""
        if len(row_data) != len(self._headers):
            return False
            
        self._data.append(row_data)
        row_index = len(self._data) - 1
        self._added_rows.add(row_index)
        
        # 发布事件
        if self.event_bus:
            from src.events import RowAddedEvent
            event = RowAddedEvent(row_index, row_data)
            self.event_bus.publish(event)
        
        # 记录变更
        change = DataChange(
            timestamp=datetime.now().isoformat(),
            change_type=ChangeType.INSERT,
            row_index=row_index,
            column_index=None,
            old_value=None,
            new_value=None,
            full_row_data=row_data.copy(),
            user_action="add_row",
            description=f"添加新行 [{row_index}]: {row_data}"
        )
        self._log_change(change)
        
        return True
    
    def insert_row(self, position: int, row_data: List[str]) -> bool:
        """在指定位置插入行"""
        if position < 0 or position > len(self._data):
            return False
        if len(row_data) != len(self._headers):
            return False
            
        self._data.insert(position, row_data)
        self._added_rows.add(position)
        
        # 发布事件
        if self.event_bus:
            from src.events import RowInsertedEvent
            event = RowInsertedEvent(position, row_data)
            self.event_bus.publish(event)
        
        # 更新修改记录中的行索引
        self._update_row_indices_after_insert(position)
        
        # 记录变更
        change = DataChange(
            timestamp=datetime.now().isoformat(),
            change_type=ChangeType.INSERT,
            row_index=position,
            column_index=None,
            old_value=None,
            new_value=None,
            full_row_data=row_data.copy(),
            user_action="insert_row",
            description=f"在位置 {position} 插入行: {row_data}"
        )
        self._log_change(change)
        
        return True
    
    def remove_row(self, row: int) -> bool:
        """删除行"""
        if 0 <= row < len(self._data):
            row_data = self._data[row].copy()
            del self._data[row]
            self._deleted_rows.add(row)
            
            # 发布事件
            if self.event_bus:
                from src.events import RowDeletedEvent
                event = RowDeletedEvent(row, row_data)
                self.event_bus.publish(event)
            
            # 更新修改记录中的行索引
            self._update_row_indices_after_delete(row)
            
            # 记录变更
            change = DataChange(
                timestamp=datetime.now().isoformat(),
                change_type=ChangeType.DELETE,
                row_index=row,
                column_index=None,
                old_value=None,
                new_value=None,
                full_row_data=row_data,
                user_action="remove_row",
                description=f"删除行 [{row}]: {row_data}"
            )
            self._log_change(change)
            
            return True
        return False
    
    def add_column(self, header: str, default_value: str = "") -> bool:
        """添加列（在末尾）"""
        result = self.insert_column(len(self._headers), header, default_value)
        
        # 发布事件
        if result and self.event_bus:
            from src.events import ColumnAddedEvent
            event = ColumnAddedEvent(len(self._headers) - 1, header)
            self.event_bus.publish(event)
        
        return result
    
    def insert_column(self, position: int, header: str, default_value: str = "") -> bool:
        """在指定位置插入列"""
        if position < 0 or position > len(self._headers):
            return False
        
        # 在指定位置插入表头
        self._headers.insert(position, header)
        
        # 为所有行在指定位置插入新列
        for row in self._data:
            row.insert(position, default_value)
        
        # 更新列顺序 - 修正列顺序的处理逻辑
        new_column_order = []
        for col_index in self._column_order:
            if col_index >= position:
                new_column_order.append(col_index + 1)
            else:
                new_column_order.append(col_index)
        # 插入新列到正确位置
        new_column_order.insert(position, position)
        self._column_order = new_column_order
        
        # 更新标记列 - 确保正确处理标记列索引
        new_marked_columns = set()
        for marked_col in self._marked_columns:
            if marked_col >= position:
                # 标记列位置在插入位置之后，需要向后移动一位
                new_marked_columns.add(marked_col + 1)
            else:
                # 标记列位置在插入位置之前，保持不变
                new_marked_columns.add(marked_col)
        self._marked_columns = new_marked_columns
        
        # 发布事件
        if self.event_bus:
            from src.events import ColumnInsertedEvent
            event = ColumnInsertedEvent(position, header, default_value)
            self.event_bus.publish(event)
        
        # 记录变更
        change = DataChange(
            timestamp=datetime.now().isoformat(),
            change_type=ChangeType.COLUMN_ADD,
            row_index=None,
            column_index=position,
            old_value=None,
            new_value=header,
            full_row_data=None,
            user_action="insert_column",
            description=f"在位置 {position} 插入列: {header}"
        )
        self._log_change(change)
        
        return True
    
    def remove_column(self, col: int) -> bool:
        """删除列"""
        if 0 <= col < len(self._headers):
            header = self._headers[col]
            del self._headers[col]
            
            # 删除所有行中的该列
            for row in self._data:
                if col < len(row):
                    del row[col]
            
            # 更新列顺序
            new_column_order = []
            for col_index in self._column_order:
                if col_index > col:
                    new_column_order.append(col_index - 1)
                elif col_index < col:
                    new_column_order.append(col_index)
            self._column_order = new_column_order
            
            # 更新标记列 - 确保正确处理
            new_marked_columns = set()
            for marked_col in self._marked_columns:
                if marked_col > col:
                    # 标记列位置在删除位置之后，需要向前移动一位
                    new_marked_columns.add(marked_col - 1)
                elif marked_col < col:
                    # 标记列位置在删除位置之前，保持不变
                    new_marked_columns.add(marked_col)
                # 如果marked_col == col，说明删除的就是标记列，直接忽略不添加
            self._marked_columns = new_marked_columns
            
            # 发布事件
            if self.event_bus:
                from src.events import ColumnRemovedEvent
                event = ColumnRemovedEvent(col, header)
                self.event_bus.publish(event)
            
            # 记录变更
            change = DataChange(
                timestamp=datetime.now().isoformat(),
                change_type=ChangeType.COLUMN_REMOVE,
                row_index=None,
                column_index=col,
                old_value=header,
                new_value=None,
                full_row_data=None,
                user_action="remove_column",
                description=f"删除列 [{col}]: {header}"
            )
            self._log_change(change)
            
            return True
        return False
    
    def get_column_order(self) -> List[int]:
        """获取列顺序"""
        return self._column_order.copy()
    
    def set_column_order(self, new_order: List[int], silent: bool = False) -> bool:
        """设置列顺序
        
        Args:
            new_order: 新的列顺序
            silent: 如果为True，则不发布事件（用于避免递归）
        """
        if len(new_order) != len(self._headers):
            return False
            
        # 如果顺序没有变化，直接返回
        if self._column_order == new_order:
            return True
            
        old_order = self._column_order.copy()
        self._column_order = new_order
        
        # 只在非静默模式下发布事件
        if not silent and self.event_bus:
            from src.events import ColumnReorderedEvent
            event = ColumnReorderedEvent(old_order, new_order)
            self.event_bus.publish(event)
        
        # 记录变更
        change = DataChange(
            timestamp=datetime.now().isoformat(),
            change_type=ChangeType.COLUMN_REORDER,
            row_index=None,
            column_index=None,
            old_value=str(old_order),
            new_value=str(new_order),
            full_row_data=None,
            user_action="reorder_columns",
            description=f"重新排序列: {old_order} -> {new_order}"
        )
        self._log_change(change)
        
        return True
    
    def get_marked_columns(self) -> Set[int]:
        """获取标记的列"""
        return self._marked_columns.copy()
    
    def set_marked_columns(self, marked_columns: Set[int]) -> bool:
        """设置标记的列"""
        old_marked = self._marked_columns.copy()
        
        # 如果新旧标记相同，则不执行任何操作
        if old_marked == marked_columns:
            return False
            
        self._marked_columns = marked_columns
        
        # 发布事件
        if self.event_bus:
            from src.events import ColumnMarkedEvent
            event = ColumnMarkedEvent(old_marked, marked_columns)
            self.event_bus.publish(event)
        
        # 记录变更
        change = DataChange(
            timestamp=datetime.now().isoformat(),
            change_type=ChangeType.COLUMN_MARK,
            row_index=None,
            column_index=None,
            old_value=str(list(old_marked)),
            new_value=str(list(marked_columns)),
            full_row_data=None,
            user_action="mark_columns",
            description=f"标记列变更: {old_marked} -> {marked_columns}"
        )
        self._log_change(change)
        
        return True
    
    def is_cell_modified(self, row: int, col: int) -> bool:
        """检查单元格是否被修改"""
        return (row, col) in self._modified_cells
    
    def is_row_deleted(self, row: int) -> bool:
        """检查行是否被删除"""
        return row in self._deleted_rows
    
    def is_row_added(self, row: int) -> bool:
        """检查行是否被新增"""
        return row in self._added_rows
    
    def is_row_disabled(self, row: int) -> bool:
        """检查行是否被禁用"""
        return row in self._disabled_rows
    
    def disable_row(self, row: int) -> bool:
        """禁用行"""
        if 0 <= row < len(self._data):
            self._disabled_rows.add(row)
            
            # 发布事件
            if self.event_bus:
                from src.events import RowStatusChangedEvent
                event = RowStatusChangedEvent([row], 'disable')
                self.event_bus.publish(event)
            
            # 记录变更
            change = DataChange(
                timestamp=datetime.now().isoformat(),
                change_type=ChangeType.UPDATE,
                row_index=row,
                column_index=None,
                old_value="enabled",
                new_value="disabled",
                full_row_data=self._data[row].copy() if row < len(self._data) else None,
                user_action="disable_row",
                description=f"禁用行 [{row}]"
            )
            self._log_change(change)
            
            return True
        return False
    
    def enable_row(self, row: int) -> bool:
        """启用行"""
        if 0 <= row < len(self._data) and row in self._disabled_rows:
            self._disabled_rows.remove(row)
            
            # 发布事件
            if self.event_bus:
                from src.events import RowStatusChangedEvent
                event = RowStatusChangedEvent([row], 'enable')
                self.event_bus.publish(event)
            
            # 记录变更
            change = DataChange(
                timestamp=datetime.now().isoformat(),
                change_type=ChangeType.UPDATE,
                row_index=row,
                column_index=None,
                old_value="disabled",
                new_value="enabled",
                full_row_data=self._data[row].copy() if row < len(self._data) else None,
                user_action="enable_row",
                description=f"启用行 [{row}]"
            )
            self._log_change(change)
            
            return True
        return False
    
    def disable_rows(self, rows: List[int]) -> bool:
        """批量禁用行"""
        success = True
        for row in rows:
            if not self.disable_row(row):
                success = False
        
        # 发布事件
        if success and self.event_bus:
            from src.events import RowStatusChangedEvent
            event = RowStatusChangedEvent(rows, 'disable')
            self.event_bus.publish(event)
        
        return success
    
    def enable_rows(self, rows: List[int]) -> bool:
        """批量启用行"""
        success = True
        for row in rows:
            if not self.enable_row(row):
                success = False
        
        # 发布事件
        if success and self.event_bus:
            from src.events import RowStatusChangedEvent
            event = RowStatusChangedEvent(rows, 'enable')
            self.event_bus.publish(event)
        
        return success
    
    def get_disabled_rows(self) -> Set[int]:
        """获取所有禁用的行"""
        return self._disabled_rows.copy()
    
    def get_modified_cells(self) -> Set[Tuple[int, int]]:
        """获取所有修改过的单元格"""
        return self._modified_cells.copy()
    
    def clear_modification_flags(self):
        """清除修改标记"""
        self._modified_cells.clear()
        self._deleted_rows.clear()
        self._added_rows.clear()
    
    def get_change_history(self, date: str = None) -> List[Dict[str, Any]]:
        """获取变更历史"""
        if date is None:
            date = datetime.now().strftime('%Y%m%d')
        
        change_file = f"changes_{date}.json"
        if os.path.exists(change_file):
            try:
                with open(change_file, 'r', encoding='utf-8') as f:
                    return json.load(f)
            except:
                return []
        return []
    
    def get_modified_rows_summary(self) -> List[Dict[str, Any]]:
        """获取所有被修改行的汇总信息，同一行只记录一次完整信息"""
        modified_rows = {}
        
        # 收集所有被修改的行
        modified_cells = self.get_modified_cells()
        for row, col in modified_cells:
            if row not in modified_rows:
                modified_rows[row] = {
                    'row_index': row,
                    'modification_type': 'cell_modified',
                    'full_row_data': self._data[row].copy() if row < len(self._data) else None,
                    'modified_columns': set()
                }
            modified_rows[row]['modified_columns'].add(col)
        
        # 添加新增的行
        for row in self._added_rows:
            if row not in modified_rows:
                modified_rows[row] = {
                    'row_index': row,
                    'modification_type': 'row_added',
                    'full_row_data': self._data[row].copy() if row < len(self._data) else None,
                    'modified_columns': set()
                }
        
        # 添加删除的行（记录删除前的数据）
        for row in self._deleted_rows:
            if row not in modified_rows:
                modified_rows[row] = {
                    'row_index': row,
                    'modification_type': 'row_deleted',
                    'full_row_data': None,  # 删除的行没有当前数据
                    'modified_columns': set()
                }
        
        # 添加禁用的行
        for row in self._disabled_rows:
            if row not in modified_rows:
                modified_rows[row] = {
                    'row_index': row,
                    'modification_type': 'row_disabled',
                    'full_row_data': self._data[row].copy() if row < len(self._data) else None,
                    'modified_columns': set()
                }
        
        # 转换为列表并排序
        result = []
        for row_data in modified_rows.values():
            # 将set转换为list以便JSON序列化
            row_data['modified_columns'] = list(row_data['modified_columns'])
            result.append(row_data)
        
        # 按行索引排序
        result.sort(key=lambda x: x['row_index'])
        
        return result
    
    def load_csv_data(self, file_path: str, encoding: str = 'utf-8', delimiter: str = ',') -> bool:
        """加载CSV数据"""
        try:
            with open(file_path, 'r', encoding=encoding) as f:
                reader = csv.reader(f, delimiter=delimiter)
                data = list(reader)
                
            if not data:
                return False
                
            self._headers = data[0]
            self._data = data[1:]
            self._column_order = list(range(len(self._headers)))
            
            # 发布事件
            if self.event_bus:
                from src.events import DataLoadedEvent
                event = DataLoadedEvent(file_path, len(self._data), len(self._headers))
                self.event_bus.publish(event)
            
            # 记录加载操作
            change = DataChange(
                timestamp=datetime.now().isoformat(),
                change_type=ChangeType.INSERT,
                row_index=None,
                column_index=None,
                old_value=None,
                new_value=None,
                full_row_data=None,
                user_action="load_csv",
                description=f"加载CSV文件: {file_path}, 行数: {len(self._data)}, 列数: {len(self._headers)}"
            )
            self._log_change(change)
            
            return True
            
        except Exception as e:
            self._logger.error(f"加载CSV文件失败: {e}")
            return False
    
    def save_csv_data(self, file_path: str, encoding: str = 'utf-8', delimiter: str = ',') -> bool:
        """保存CSV数据"""
        try:
            with open(file_path, 'w', encoding=encoding, newline='') as f:
                writer = csv.writer(f, delimiter=delimiter)
                writer.writerow(self._headers)
                writer.writerows(self._data)
            
            # 发布事件
            if self.event_bus:
                from src.events import DataSavedEvent
                event = DataSavedEvent(file_path, len(self._data), len(self._headers))
                self.event_bus.publish(event)
            
            # 记录保存操作
            change = DataChange(
                timestamp=datetime.now().isoformat(),
                change_type=ChangeType.INSERT,
                row_index=None,
                column_index=None,
                old_value=None,
                new_value=None,
                full_row_data=None,
                user_action="save_csv",
                description=f"保存CSV文件: {file_path}, 行数: {len(self._data)}, 列数: {len(self._headers)}"
            )
            self._log_change(change)
            
            return True
            
        except Exception as e:
            self._logger.error(f"保存CSV文件失败: {e}")
            return False
